/*
 *   Copyright 2023 <a href="mailto:asialjim@hotmail.com">Asial Jim</a>
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */
package com.asialjim.encommunicate.rsa.management.service;

import com.asialjim.encommunicate.base.rsa.RSAKeyPairProperty;
import com.asialjim.encommunicate.base.rsa.key.RSAClientKey;
import com.asialjim.encommunicate.base.rsa.key.RSAKeySize;
import com.asialjim.encommunicate.base.rsa.key.RSAKeys;
import com.asialjim.encommunicate.base.rsa.key.RSAServerKey;
import com.asialjim.encommunicate.rsa.management.key.RSAKeyLookUpComponent;
import com.asialjim.encommunicate.rsa.management.key.RSAKeysEvent;
import com.asialjim.encommunicate.rsa.management.pojo.AppEnDecryptInfo;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.Objects;
import java.util.Set;

/**
 * RSA 密钥对生成
 *
 * @author Copyright © <a href="mailto:asialjim@hotmail.com">Asial Jim</a>   Co., LTD
 * @version 1.0
 * @since 2023/2/27, &nbsp;&nbsp; <em>version:1.0</em>, &nbsp;&nbsp; <em>java version:17</em>
 */
@Component
public class RSAGenerateService implements ApplicationContextAware {
    @Setter private ApplicationContext applicationContext;
    @Autowired(required = false) private RSAKeyLookUpComponent rsaKeyLookUpComponent;

    public Set<AppEnDecryptInfo> infos() {
        return rsaKeyLookUpComponent.infos();
    }

    /**
     * 生成密钥对
     *
     * @param appid      {@link String appid}
     * @param rsaKeySize {@link RSAKeySize 密钥长度}
     * @return {@link RSAKeys 密钥对}
     * @since 2023/2/27
     */
    public RSAKeys generateRSAKey(String appid, RSAKeySize rsaKeySize, String name) {
        // 优先查找系统是否存在密钥对，若存在，则直接返回
        if (Objects.nonNull(this.rsaKeyLookUpComponent)) {
            RSAClientKey rsaClientKey = rsaKeyLookUpComponent.clientKeyNullable(appid);
            RSAServerKey rsaServerKey = rsaKeyLookUpComponent.serverKeyNullable(appid);
            if (Objects.nonNull(rsaClientKey) && Objects.nonNull(rsaServerKey))
                return RSAKeys.builder().appid(appid).clientKey(rsaClientKey).serverKey(rsaServerKey).build();
        }

        // 生成两套密钥对
        RSAKeyPairProperty rsaKeyPairA = RSAKeyPairProperty.createRSAKeyPair(rsaKeySize);
        RSAKeyPairProperty rsaKeyPairB = RSAKeyPairProperty.createRSAKeyPair(rsaKeySize);

        // 分别组装客户端密钥对和服务端密钥对
        RSAClientKey clientKey = RSAClientKey.builder().appid(appid).pubKey(rsaKeyPairA.getPubKey()).priKey(rsaKeyPairB.getPriKey()).build();
        RSAServerKey serverKey = RSAServerKey.builder().appid(appid).pubKey(rsaKeyPairB.getPubKey()).priKey(rsaKeyPairA.getPriKey()).build();

        // 组装应用密钥对
        RSAKeys keys = RSAKeys.builder().appid(appid).name(name).clientKey(clientKey).serverKey(serverKey).build();

        // 发布密钥对生成事件
        if (Objects.nonNull(applicationContext))
            applicationContext.publishEvent(new RSAKeysEvent(keys));
        return keys;
    }

    /**
     * 生成密钥对
     *
     * @param appid      {@link String appid}
     * @param rsaKeySize {@link Integer 密钥对长度}
     * @return {@link RSAKeys 密钥对}
     * @since 2023/2/27
     */
    public RSAKeys generateRSAKey(String appid, Integer rsaKeySize, String name) throws Throwable {
        return generateRSAKey(appid, RSAKeySize.sizeOf(rsaKeySize), name);
    }

    /**
     * 生成密钥对
     *
     * @param appid      {@link String appid}
     * @param rsaKeySize {@link Integer 密钥对长度}
     * @return {@link RSAKeys 密钥对}
     * @since 2023/2/27
     */
    public RSAClientKey generateClientKey(String appid, Integer rsaKeySize, String name) throws Throwable {
        return generateRSAKey(appid, rsaKeySize, name).getClientKey();
    }

    public RSAClientKey generateClientKey(String appid) {
        return rsaKeyLookUpComponent.clientKeyNullable(appid);
    }

    public Set<AppEnDecryptInfo> modify(AppEnDecryptInfo body) {
        return rsaKeyLookUpComponent.modify(body);
    }
}